/*
 * ProFisher 2
 *
 * Credits:
 * Last Man 3 - Updater, PvP Support, Welcome Screen wait, Sounds, Click continue
 * pkiller - for the use of his account.
 *
 * Testers:
 * Coobot, jared, dave[wowsucks], Drewley, i spoon squirrels, Beef n go[8675309]
 */
import java.awt.Color;
import java.awt.Graphics;
import java.util.Map;

import com.speljohan.rsbot.accessors.Player;
import com.speljohan.rsbot.bot.Bot;
import com.speljohan.rsbot.event.events.ServerMessageEvent;
import com.speljohan.rsbot.event.listeners.PaintListener;
import com.speljohan.rsbot.event.listeners.ServerMessageListener;
import com.speljohan.rsbot.script.Constants;
import com.speljohan.rsbot.script.Script;
import com.speljohan.rsbot.script.wrappers.RSInterface;
import com.speljohan.rsbot.script.wrappers.RSItemTile;
import com.speljohan.rsbot.script.wrappers.RSNPC;
import com.speljohan.rsbot.script.wrappers.RSObject;
import com.speljohan.rsbot.script.wrappers.RSPlayer;
import com.speljohan.rsbot.script.wrappers.RSTile;

public class ProFisher2 extends Script implements ServerMessageListener,
		PaintListener {
	// State constants:
	public final int S_WALKTO_BANK = 100;
	public final int S_WALKTO_SPOT = 200;
	public final int S_FISH = 300;
	public final int S_DROP_ALL = 400;
	public final int S_USE_BANK = 500;
	public final int S_DEPOSIT = 600;
	public final int S_WITHDRAW = 700;

	// Bait constants:
	public final int BAIT_NONE = -1;
	public final int BAIT_BAIT = 313;
	public final int BAIT_FEATHERS = 314;
	public final int BAIT_STRIPY = 10087;

	// Gear constants:
	public final int GEAR_NET = 303;
	public final int GEAR_ROD = 307;
	public final int GEAR_FLYROD = 309;
	public final int GEAR_CAGE = 301;
	public final int GEAR_HARPOON = 311;
	public final int GEAR_BIGNET = 305;

	// Paths and tiles:
	public RSTile[] toBank;
	public RSTile[] toArea;
	RSTile[] lostTiles = new RSTile[] { new RSTile(2860, 3428),
			new RSTile(2863, 2978), new RSTile(2835, 2975) };
	RSTile[] recoverTiles = new RSTile[] { new RSTile(2849, 3430),
			new RSTile(2855, 2971), new RSTile(2850, 2970) };

	// Runtime configuration.
	public int currentGear;
	public int currentBait;
	public String currentCommand;
	public int fishingSpotID;
	public int bankID;
	public boolean usesNPCBanking;

	// Script configuration.
	public String locationName;
	public String catchName;
	public boolean barbarianMode;
	public boolean powerMode;
	public boolean usePaint;
	public boolean Sound;
	public boolean isPvP;

	// Misc variables.
	public int currentFails = 0;
	public int randomRunEnergy;
	public int state = S_FISH;
	public boolean runningFromCombat;
	public long scriptStartTime;
	public int playerStartXP;
	public int numberOfCatches;
	public long lastCheck;
	public long checkTime;
	public int timesAvoidedCombat;
	public int whirlpoolsAvoided;
	public int timesRecoveredGear;
	public int startLevel;
	public int lastExp;
	public int updateCheck = 0;
	public RSPlayer PvPPlayer;
	public int sCB;
	public boolean sRM;
	public boolean StartedY;

	public int[] whirlpools = new int[] { 403, 404, 406, 406 };

	int antiBan() {
		final int GambleInt = random(1, 6);

		switch (GambleInt) {
		case 1:
			wait(random(1000, 1500));
			break;

		case 2:
			if (random(1, 4) == 1) {
				final int x = random(0, 750);
				final int y = random(0, 500);
				moveMouse(0, 0, x, y);
			}
			return random(1000, 1500);

		case 3:
			// Is the current tab the inventory?
			if (getCurrentTab() != Constants.TAB_INVENTORY) {
				// No, so switch to the inventory tab.
				openTab(Constants.TAB_INVENTORY);
				return random(500, 750);
			} else {
				// No, so return
				return random(500, 750);
			}

		case 4:
			// If the player is moving, then abort.
			if (getMyPlayer().isMoving()) {
				return random(750, 1000);
			}

			if (System.currentTimeMillis() - lastCheck >= checkTime) {
				lastCheck = System.currentTimeMillis();
				checkTime = random(60000, 180000);

				if (getCurrentTab() != Constants.TAB_STATS) {
					openTab(Constants.TAB_STATS);
				}
				moveMouse(663, 292, 50, 28);
				return random(5000, 8000);
			}

		case 5:
			if (random(1, 8) == 2) {
				int angle = getCameraAngle() + random(-90, 90);
				if (angle < 0) {
					angle = 0;
				}
				if (angle > 359) {
					angle = 0;
				}

				setCameraRotation(angle);
			}
			return random(500, 750);
		}

		return random(500, 1000);
	}

	public void beep(final int count) {
		if (!Sound) {
			return;
		}
		for (int i = 0; i < count; i++) {
			java.awt.Toolkit.getDefaultToolkit().beep();
			wait(250);
		}
		wait(random(100, 500));
		return;
	}

	public boolean checkAndAvoidWhirlpools() {
		final RSTile playerLocation = getMyPlayer().getLocation();
		final RSTile tileToTest1 = new RSTile(playerLocation.getX() + 1,
				playerLocation.getY());
		final RSTile tileToTest2 = new RSTile(playerLocation.getX() - 1,
				playerLocation.getY());
		final RSTile tileToTest3 = new RSTile(playerLocation.getX(),
				playerLocation.getY() + 1);
		final RSTile tileToTest4 = new RSTile(playerLocation.getX(),
				playerLocation.getY() - 1);

		for (final int id : whirlpools) {
			final RSNPC whirlpool = getNearestNPCByID(id);

			if (whirlpool == null) {
				continue;
			}

			if (whirlpool.getLocation().equals(tileToTest1)
					|| whirlpool.getLocation().equals(tileToTest2)
					|| whirlpool.getLocation().equals(tileToTest3)
					|| whirlpool.getLocation().equals(tileToTest4)) {
				whirlpoolsAvoided++;
				log("Found whirlpool");
				return true;
			}
		}

		return false;
	}

	public boolean checkAndRecoverGear() {
		final RSItemTile itemTile = getGroundItemByID(currentGear);

		if (barbarianMode) {
			return false;
		}

		if (getInventoryCount(currentGear) == 0 && itemTile != null) {
			if (tileOnScreen(itemTile)) {
				timesRecoveredGear++;
				log("Recovered gear.");
				atTile(itemTile, "Take");
				return true;
			} else {
				log("Walking to gear location.");
				walkTileMM(itemTile);
				return true;
			}
		} else {
			return false;
		}
	}

	public boolean checkForLogout() {
		for (int failed = 0; failed < 3; failed++) {
			logout();
			beep(3);
			wait(500);
			if (!isLoggedIn()) {
				return true;
			}
		}
		return false;
	}

	public boolean checkLostAndRecover() {
		int index = 0;
		for (final RSTile lost : lostTiles) {
			if (distanceTo(lost) <= 2) {
				final RSTile destination = randomizeTile(recoverTiles[index],
						2, 2);
				log("Lost at " + lost.getX() + ", " + lost.getY()
						+ ", recovering.");
				walkTileMM(destination);
				return true;
			}

			index++;
		}

		return false;

	}

	public void checkPvP() {
		final int myCB = getMyPlayer().getCombatLevel();
		final int CBdiff = (int) (myCB * 0.10 + 5);
		int CBmin = myCB - CBdiff;
		final int CBmax = myCB + CBdiff + 1;
		if (CBmin < 20) {
			CBmin = 20;
		}
		if (sCB == 0) {
			sCB = getMyPlayer().getCombatLevel();
		}
		if (myCB != sCB) {
			sRM = false;
			sCB = getMyPlayer().getCombatLevel();
		}
		if (isLoggedIn() && CBmin > 12 && CBmax > 25 && !sRM) {
			log("Logging out if any player in combat range: " + CBmin + "-"
					+ CBmax + " is comming");
			sRM = true;
		}
		if (playerInRange(CBmin, CBmax)) {
			log(PvPPlayer.getName() + " - level " + PvPPlayer.getCombatLevel()
					+ " is coming... Logout!");
			if (checkForLogout()) {
				stopAllScripts();
			}
		}
		return;
	}

	public boolean clickcontinue() {
		if (getContinueChildInterface() != null) {
			if (getContinueChildInterface().getText().contains("to continue")) {
				return atInterface(getContinueChildInterface());
			}
		}
		return false;
	}

	public int depositAll() {
		// Make an array of items to keep.
		final int[] thingsToKeep = new int[] { currentGear, currentBait, 995 };

		if (!RSInterface.getInterface(Constants.INTERFACE_BANK).isValid()) {
			state = S_USE_BANK;
			return 500;
		}

		// Deposit all.
		bank.depositAllExcept(thingsToKeep);

		// Only switch states if thet deposit was successfull.
		if (!isInventoryFull()) {
			state = S_WALKTO_SPOT;
		} else {
			state = S_USE_BANK;
		}

		return random(500, 750);
	}

	public int dropAll() {
		// Make an array of items to keep.
		final int[] thingsToKeep = new int[] { currentGear, currentBait, 995 };

		// Drop all, twice to make sure nothing is missed.
		dropAllExcept(thingsToKeep);
		dropAllExcept(thingsToKeep);
		dropAllExcept(thingsToKeep);
		dropAllExcept(thingsToKeep);

		state = S_FISH;

		return random(500, 750);
	}

	/*
	 * This method returns the script's author's name.
	 */
	public String getAuthor() {
		return "Aelin";
	}

	/*
	 * This method returns the script's name.
	 */
	public String getName() {
		return "ProFisher 2";
	}

	/*
	 * This method returns the script's category.
	 */
	public String getScriptCategory() {
		// Don't fucking change this. /facepalm
		return "Fishing";
	}

	/*
	 * This script return's the html used by the script selector.
	 */
	public String getScriptDescription() {
		String html = "<html>";
		html += "<head>";
		html += "<style type=\"text/css\"> hr {color: white} p {margin-left: 20px}</style>";
		html += "</head>";
		html += "<body>";
		html += "<center>";
		html += "<b><font size=\"4\" color=\"red\">" + getName() + " v"
				+ getVersion() + "</font></b><br>";
		html += "</center>";
		html += "<center><table border=\"0\"><tr><td colspan=\"2\"><center><font size=\"4\"><b>:: Script Settings ::</b></font></center></td></tr><tr><td colspan=\"2\"><hr></td></tr><tr><td>";
		html += "<tr><td><b>Location: </b></td><td><center><select name=\"locationName\">";
		html += "<option>Barbarian Village";
		html += "<option>Catherby";
		html += "<option>Draynor";
		html += "<option>Fishing Guild";
		html += "<option>Karamja";
		html += "<option>Shilo"; // 499 = banker npc
		html += "<option>Piscatoris";
		html += "</select></center></td></tr>";
		html += "<tr><td><b>Catch: </b></td><td><center><select name=\"catchName\">";
		html += "<option>Pike";
		html += "<option>Bass/Cod/Mackerel";
		html += "<option>Shrimp/Anchovies";
		html += "<option>Herring/Sardines";
		html += "<option>Trout/Salmon";
		html += "<option>Tuna/Swordfish";
		html += "<option>Lobsters";
		html += "<option>Sharks";
		html += "<option>Rainbow Fish";
		html += "<option>Monkfish";
		html += "</select></center></td></tr>";
		html += "<tr><td><b>Barbarian Mode:</b></td><td><center><input type=\"checkbox\" name=\"barbarianMode\" value=\"true\"><B>Yes</b></center></td></tr>";
		html += "<tr><td><b>Powerfishing Mode:</b></td><td><center><input type=\"checkbox\" name=\"powerMode\" value=\"true\"><B>Yes</b></center></td></tr>";
		html += "<tr><td><b>PvP World Mode:</b></td><td><center><input type=\"checkbox\" name=\"PvPWorld\" value=\"true\"><B>Yes</b></center></td></tr>";
		html += "<tr><td><b>Sounds:</b></td><td><center><input type=\"checkbox\" name=\"wSound\" value=\"true\"><B>Yes</b></center></td></tr>";
		html += "<tr><td><b>Use Debug Paint:</b></td><td><center><input type=\"checkbox\" name=\"usePaint\" checked=\"true\" value=\"true\"><B>Yes</b></center></td></tr>";
		html += "</table>";
		html += "</center></body>";
		html += "</html>";

		return html;
	}

	/*
	 * This method returns the script's version.
	 */
	public double getVersion() {
		return 0.9;
	}

	public boolean isWelcomeButton() {
		final RSInterface welcomeInterface = RSInterface.getInterface(378);
		if (welcomeInterface.getChild(45).getAbsoluteX() > 20
				|| !welcomeInterface.getChild(117).getText().equals(
						"10.1120.190")
				&& !welcomeInterface.getChild(117).getText().equals("")) {
			log("We still are in Welcome Screen");
			return true;
		} else {
			return false;
		}
	}

	public int loop() {
		updateCheck++;
		if (updateCheck > 100) {
			updateCheck = 0;
		}
		if (!isLoggedIn() || isWelcomeButton() || !StartedY) {
			StartedY = true;
			wait(1000);
			return random(250, 500);
		}
		if (barbarianMode && currentGear != GEAR_HARPOON) {
			log("Barbarian mode is only for harpoon modes.");
			if (checkForLogout()) {
				stopAllScripts();
			}
		}

		if (currentFails >= 25) {
			log("The script failed 25 times, and will now stop as a failsafe.");
			if (checkForLogout()) {
				stopAllScripts();
			}
		}

		if (isPvP) {
			checkPvP();
		}

		switch (state) {
		case S_WALKTO_BANK:
			return walkToBank();

		case S_WALKTO_SPOT:
			return walkToSpots();

		case S_FISH:
			return stateFish();

		case S_DROP_ALL:
			return dropAll();

		case S_USE_BANK:
			if (usesNPCBanking) {
				if (locationName.equals("Piscatoris")) {
					return useBankNPCPiscatoris();
				} else {
					return useBankNPC();
				}
			} else {
				return useBank();
			}

		case S_DEPOSIT:
			return depositAll();

		case S_WITHDRAW:
			stopAllScripts();
		}

		return random(500, 1000);
	}

	public void onFinish() {
		// Remove listeners.
		Bot.getEventManager().removeListener(PaintListener.class, this);
		Bot.getEventManager().removeListener(ServerMessageListener.class, this);
	}

	public void onRepaint(final Graphics g) {
		long runTime = 0;
		long seconds = 0;
		long minutes = 0;
		long hours = 0;
		int expGained = 0;
		int levelsGained;

		//
		if (lastExp == 0) {
			lastExp = skills.getCurrentSkillExp(Constants.STAT_FISHING);
		}

		if (skills.getCurrentSkillExp(Constants.STAT_FISHING) > lastExp) {
			lastExp = skills.getCurrentSkillExp(Constants.STAT_FISHING);
			numberOfCatches++;
		}

		// Return if paint is disabled.
		if (!usePaint) {
			return;
		}

		//
		if (playerStartXP == 0) {
			playerStartXP = skills.getCurrentSkillExp(Constants.STAT_FISHING);
		}

		if (startLevel == 0) {
			startLevel = skills.getCurrentSkillLevel(Constants.STAT_FISHING);
		}

		// Calculate current runtime.
		runTime = System.currentTimeMillis() - scriptStartTime;
		seconds = runTime / 1000;
		if (seconds >= 60) {
			minutes = seconds / 60;
			seconds -= minutes * 60;
		}
		if (minutes >= 60) {
			hours = minutes / 60;
			minutes -= hours * 60;
		}

		// Calculate experience gained.
		expGained = skills.getCurrentSkillExp(Constants.STAT_FISHING)
				- playerStartXP;
		g.setColor(new Color(255, 0, 0, 50));
		final int[][] paint = new int[][] {
				new int[] { 136, 152, 168, 184, 200, 216, 232, 248, 264, 280,
						296, 312, 328 }, new int[] { 152, 186 } };
		if (barbarianMode) {
			paint[1][0] -= 16;
			paint[1][1] += 16;
		}
		if (powerMode) {
			paint[1][0] -= 16;
			paint[1][1] += 16;
		}
		g.fillRoundRect(4, paint[1][0], 200, paint[1][1], 10, 10);

		// Calculate levels gained
		levelsGained = skills.getCurrentSkillLevel(Constants.STAT_FISHING)
				- startLevel;

		g.setColor(Color.WHITE);
		if (barbarianMode || powerMode) {
			if (powerMode && !barbarianMode) {
				g.drawString(getName() + " v" + getVersion(), 12, paint[0][1]);
				g.drawString("Fishing location: " + locationName, 12,
						paint[0][2]);
				g.drawString("Fishing for: " + catchName, 12, paint[0][3]);
				g.drawString("Powerfishing Mode Active", 12, paint[0][4]);
				g.drawString("Run time: " + hours + ":" + minutes + ":"
						+ seconds, 12, paint[0][5]);
				g.drawString("Catches: " + numberOfCatches, 12, paint[0][6]);
				g.drawString("XP Gained: " + expGained, 12, paint[0][7]);
				g.drawString("Levels Gained: " + levelsGained, 12, paint[0][8]);
				g.drawString("Percent to next level: "
						+ skills.getPercentToNextLevel(Constants.STAT_FISHING),
						12, paint[0][9]);
				g.drawString("Times Avoided Combat: " + timesAvoidedCombat, 12,
						paint[0][10]);
				g.drawString("Whirlpools avoided: " + whirlpoolsAvoided, 12,
						paint[0][11]);
				g.drawString("Times recovered gear: " + timesRecoveredGear, 12,
						paint[0][12]);
			}
			if (!powerMode && barbarianMode) {
				g.drawString(getName() + " v" + getVersion(), 12, paint[0][1]);
				g.drawString("Fishing location: " + locationName, 12,
						paint[0][2]);
				g.drawString("Fishing for: " + catchName, 12, paint[0][3]);
				g.drawString("Barbarian Mode Active", 12, paint[0][4]);
				g.drawString("Run time: " + hours + ":" + minutes + ":"
						+ seconds, 12, paint[0][5]);
				g.drawString("Catches: " + numberOfCatches, 12, paint[0][6]);
				g.drawString("XP Gained: " + expGained, 12, paint[0][7]);
				g.drawString("Levels Gained: " + levelsGained, 12, paint[0][8]);
				g.drawString("Percent to next level: "
						+ skills.getPercentToNextLevel(Constants.STAT_FISHING),
						12, paint[0][9]);
				g.drawString("Times Avoided Combat: " + timesAvoidedCombat, 12,
						paint[0][10]);
				g.drawString("Whirlpools avoided: " + whirlpoolsAvoided, 12,
						paint[0][11]);
				g.drawString("Times recovered gear: " + timesRecoveredGear, 12,
						paint[0][12]);
			}
			if (powerMode && barbarianMode) {
				g.drawString(getName() + " v" + getVersion(), 12, paint[0][0]);
				g.drawString("Fishing location: " + locationName, 12,
						paint[0][1]);
				g.drawString("Fishing for: " + catchName, 12, paint[0][2]);
				g.drawString("Powerfishing Mode Active", 12, paint[0][3]);
				g.drawString("Barbarian Mode Active", 12, paint[0][4]);
				g.drawString("Run time: " + hours + ":" + minutes + ":"
						+ seconds, 12, paint[0][5]);
				g.drawString("Catches: " + numberOfCatches, 12, paint[0][6]);
				g.drawString("XP Gained: " + expGained, 12, paint[0][7]);
				g.drawString("Levels Gained: " + levelsGained, 12, paint[0][8]);
				g.drawString("Percent to next level: "
						+ skills.getPercentToNextLevel(Constants.STAT_FISHING),
						12, paint[0][9]);
				g.drawString("Times Avoided Combat: " + timesAvoidedCombat, 12,
						paint[0][10]);
				g.drawString("Whirlpools avoided: " + whirlpoolsAvoided, 12,
						paint[0][11]);
				g.drawString("Times recovered gear: " + timesRecoveredGear, 12,
						paint[0][12]);
			}
		} else {
			g.drawString(getName() + " v" + getVersion(), 12, paint[0][2]);
			g.drawString("Fishing location: " + locationName, 12, paint[0][3]);
			g.drawString("Fishing for: " + catchName, 12, paint[0][4]);
			g.drawString("Run time: " + hours + ":" + minutes + ":" + seconds,
					12, paint[0][5]);
			g.drawString("Catches: " + numberOfCatches, 12, paint[0][6]);
			g.drawString("XP Gained: " + expGained, 12, paint[0][7]);
			g.drawString("Levels Gained: " + levelsGained, 12, paint[0][8]);
			g.drawString("Percent to next level: "
					+ skills.getPercentToNextLevel(Constants.STAT_FISHING), 12,
					paint[0][9]);
			g.drawString("Times Avoided Combat: " + timesAvoidedCombat, 12,
					paint[0][10]);
			g.drawString("Whirlpools avoided: " + whirlpoolsAvoided, 12,
					paint[0][11]);
			g.drawString("Times recovered gear: " + timesRecoveredGear, 12,
					paint[0][12]);
		}
	}

	/*
	 * Pre-runtime configuration takes place within this method.
	 */
	public boolean onStart(final Map<String, String> args) {
		Reset();

		// Set script start time
		scriptStartTime = System.currentTimeMillis();

		// Load script configuration from arguements.
		locationName = args.get("locationName");
		catchName = args.get("catchName");
		barbarianMode = args.get("barbarianMode") != null ? true : false;
		powerMode = args.get("powerMode") != null ? true : false;
		usePaint = args.get("usePaint") != null ? true : false;
		isPvP = args.get("PvPWorld") != null ? true : false;
		Sound = args.get("wSound") != null ? true : false;

		// Barbarian Village locations:
		if (locationName.equals("Barbarian Village")) {
			log("Setting paths for Barbarian Village.");
			toBank = new RSTile[] { new RSTile(3106, 3433),
					new RSTile(3094, 3439), new RSTile(3094, 3454),
					new RSTile(3099, 3465), new RSTile(3100, 3480),
					new RSTile(3093, 3491) };
			toArea = reversePath(toBank);
			usesNPCBanking = false;

			if (catchName.equals("Pike")) {
				currentGear = GEAR_ROD;
				currentBait = BAIT_BAIT;
				fishingSpotID = 328;
				currentCommand = "Bait";
				bankID = 26972;
				return true;
			}

			if (catchName.equals("Trout/Salmon")) {
				currentGear = GEAR_FLYROD;
				currentBait = BAIT_FEATHERS;
				fishingSpotID = 328;
				currentCommand = "Lure";
				bankID = 26972;
				return true;
			}

			if (catchName.equals("Rainbow Fish")) {
				currentGear = GEAR_FLYROD;
				currentBait = BAIT_STRIPY;
				fishingSpotID = 328;
				currentCommand = "Lure";
				bankID = 26972;
				return true;
			}
		}

		// Catherby locations:
		if (locationName.equals("Catherby")) {
			log("Setting paths for Catherby.");
			toBank = new RSTile[] { new RSTile(2848, 3430),
					new RSTile(2839, 3435), new RSTile(2822, 3438),
					new RSTile(2810, 3440) };
			toArea = reversePath(toBank);
			usesNPCBanking = false;

			if (catchName.equals("Bass/Cod/Mackerel")) {
				currentGear = GEAR_BIGNET;
				currentBait = BAIT_NONE;
				fishingSpotID = 322;
				currentCommand = "Net";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Shrimp/Anchovies")) {
				currentGear = GEAR_NET;
				currentBait = BAIT_NONE;
				fishingSpotID = 320;
				currentCommand = "Net";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Herring/Sardines")) {
				currentGear = GEAR_ROD;
				currentBait = BAIT_BAIT;
				fishingSpotID = 320;
				currentCommand = "Bait";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Lobsters")) {
				currentGear = GEAR_CAGE;
				currentBait = BAIT_NONE;
				fishingSpotID = 321;
				currentCommand = "Cage";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Tuna/Swordfish")) {
				currentGear = GEAR_HARPOON;
				currentBait = BAIT_NONE;
				fishingSpotID = 321;
				currentCommand = "Harpoon";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Sharks")) {
				currentGear = GEAR_HARPOON;
				currentBait = BAIT_NONE;
				fishingSpotID = 322;
				currentCommand = "Harpoon";
				bankID = 2213;
				return true;
			}
		}

		// Draynor locations.
		if (locationName.equals("Draynor")) {
			// Setup draynor paths.
			log("Setting paths for Draynor.");
			toBank = new RSTile[] { new RSTile(3087, 3230),
					new RSTile(3084, 3240), new RSTile(3094, 3243) };
			toArea = reversePath(toBank);
			usesNPCBanking = false;

			if (catchName.equals("Shrimp/Anchovies")) {
				currentGear = GEAR_NET;
				currentBait = BAIT_NONE;
				fishingSpotID = 327;
				currentCommand = "Net";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Herring/Sardines")) {
				currentGear = GEAR_ROD;
				currentBait = BAIT_BAIT;
				fishingSpotID = 327;
				currentCommand = "Bait";
				bankID = 2213;
				return true;
			}
		}

		if (locationName.equals("Fishing Guild")) {
			log("Setting paths for the Fishing Guild.");
			toBank = new RSTile[] { new RSTile(2599, 3421),
					new RSTile(2594, 3414), new RSTile(2588, 3420) };
			toArea = reversePath(toBank);
			usesNPCBanking = false;

			if (catchName.equals("Bass/Cod/Mackerel")) {
				currentGear = GEAR_BIGNET;
				currentBait = BAIT_NONE;
				fishingSpotID = 313;
				currentCommand = "Net";
				bankID = 2213;
				return true;
			}
			if (catchName.equals("Lobsters")) {
				currentGear = GEAR_CAGE;
				currentBait = BAIT_NONE;
				fishingSpotID = 312;
				currentCommand = "Cage";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Tuna/Swordfish")) {
				currentGear = GEAR_HARPOON;
				currentBait = BAIT_NONE;
				fishingSpotID = 312;
				currentCommand = "Harpoon";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Sharks")) {
				currentGear = GEAR_HARPOON;
				currentBait = BAIT_NONE;
				fishingSpotID = 313;
				currentCommand = "Harpoon";
				bankID = 2213;
				return true;
			}
		}

		if (locationName.equals("Karamja")) {
			log("Setting paths for Karamja");
			toBank = new RSTile[] { new RSTile(2925, 3176),
					new RSTile(2925, 3163), new RSTile(2926, 3150),
					new RSTile(2938, 3146), /*
											 * new RSTile(2954, 3147), new
											 * RSTile(3029, 3217),
											 */new RSTile(3028, 3231),
					new RSTile(3041, 3245), new RSTile(3040, 3259),
					new RSTile(3053, 3269), new RSTile(3067, 3276),
					new RSTile(3078, 3266), new RSTile(3081, 3250),
					new RSTile(3094, 3243) };
			toArea = reversePath(toBank);
			usesNPCBanking = false;

			if (catchName.equals("Shrimp/Anchovies")) {
				currentGear = GEAR_NET;
				currentBait = BAIT_NONE;
				fishingSpotID = 323;
				currentCommand = "Net";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Herring/Sardines")) {
				currentGear = GEAR_ROD;
				currentBait = BAIT_BAIT;
				fishingSpotID = 323;
				currentCommand = "Bait";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Lobsters")) {
				currentGear = GEAR_CAGE;
				currentBait = BAIT_NONE;
				fishingSpotID = 324;
				currentCommand = "Cage";
				bankID = 2213;
				return true;
			}

			if (catchName.equals("Tuna/Swordfish")) {
				currentGear = GEAR_HARPOON;
				currentBait = BAIT_NONE;
				fishingSpotID = 324;
				currentCommand = "Harpoon";
				bankID = 2213;
				return true;
			}
		}

		if (locationName.equals("Shilo")) {
			log("Setting paths for Shilo.");
			toBank = new RSTile[] { new RSTile(2855, 2971),
					new RSTile(2848, 2965), new RSTile(2852, 2954) };
			toArea = reversePath(toBank);
			usesNPCBanking = true;

			if (catchName.equals("Trout/Salmon")) {
				currentGear = GEAR_FLYROD;
				currentBait = BAIT_FEATHERS;
				fishingSpotID = 317;
				currentCommand = "Lure";
				bankID = 499;
				return true;
			}

			if (catchName.equals("Pike")) {
				currentGear = GEAR_ROD;
				currentBait = BAIT_BAIT;
				fishingSpotID = 317;
				currentCommand = "Bait";
				bankID = 499;
				return true;
			}
		}

		if (locationName.equals("Piscatoris")) {
			log("Setting paths for Piscatoris");
			toBank = new RSTile[] { new RSTile(2346, 3701),
					new RSTile(2339, 3692), new RSTile(2330, 3689) };
			toArea = reversePath(toBank);
			usesNPCBanking = true;

			if (catchName.equals("Monkfish")) {
				currentGear = GEAR_NET;
				currentBait = BAIT_NONE;
				fishingSpotID = 3848;
				currentCommand = "Net";
				bankID = 3824;
				return true;
			}

			if (catchName.equals("Tuna/Swordfish")) {
				currentGear = GEAR_HARPOON;
				currentBait = BAIT_NONE;
				fishingSpotID = 3848;
				currentCommand = "Harpoon";
				bankID = 3824;
				return true;
			}
		}
		log("Unable to start script: Invalid combination of parameters.");
		return false;
	}

	public boolean playerInRange(final int min, final int max) {
		final int[] validPlayers = Bot.getClient().getPlayerIndexArray();
		final Player[] players = Bot.getClient().getPlayerArray();
		for (final int element : validPlayers) {
			if (players[element] == null) {
				continue;
			}
			PvPPlayer = new RSPlayer(players[element]);
			try {
				if (PvPPlayer.getCombatLevel() >= min
						&& PvPPlayer.getCombatLevel() <= max) {
					return true;
				}
			} catch (final Exception e) {
			}
		}
		return false;
	}

	public void Reset() {
		StartedY = false;
		currentFails = 0;
	}

	public void serverMessageRecieved(final ServerMessageEvent arg0) {
		final String serverString = arg0.getMessage();
		if (serverString.contains("You've just advanced")) {
			log("We leveled up!");
			beep(1);
			clickcontinue();
		}
		if (serverString.contains("Oh dear")) {
			log("You died!!");
			beep(5);
		}
	}

	public int stateFish() {
		// Find fishing spot.
		final RSNPC fishingSpot = getNearestNPCByID(fishingSpotID);

		//
		if (currentBait != BAIT_NONE && getInventoryCount(currentBait) == 0) {
			log("No bait for current mode.");
			currentFails += 5;
			return random(250, 500);
		}

		//
		if (checkAndRecoverGear()) {
			return random(1000, 1500);
		}

		if (getInventoryCount(currentGear) == 0 && !barbarianMode) {
			log("No gear for the current mode.");
			currentFails += 5;
			return random(250, 500);
		}

		// Is the player currently in combat?
		if (getMyPlayer().isInCombat()) {
			log("Running from combat.");
			runningFromCombat = true;
			state = S_WALKTO_BANK;
			timesAvoidedCombat++;
			return random(250, 500);
		}

		// Is the player's inventory full?
		if (isInventoryFull()) {
			openTab(Constants.TAB_INVENTORY);
			log("The inventory is full, "
					+ (powerMode == true ? "dropping all catches."
							: "heading to the bank."));
			state = powerMode == true ? S_DROP_ALL : S_WALKTO_BANK;
			return random(250, 500);
		}

		// Is the player current busy? If so, do antiban.
		if (getMyPlayer().getAnimation() != -1 && !checkAndAvoidWhirlpools()
				|| getMyPlayer().isMoving()) {
			return antiBan();
		}

		if (fishingSpot == null) {
			if (checkLostAndRecover()) {
				return random(500, 750);
			}
			if (distanceTo(toBank[toBank.length - 1]) <= 3) {
				state = S_WALKTO_SPOT;
				return random(750, 1500);
			}

			currentFails++;
			log("Unable to find fishing spot.");
			return random(250, 500);
		} else {
			if (tileOnScreen(fishingSpot.getLocation())) {
				if (!atNPC(fishingSpot, currentCommand)) {
					setCameraRotation(random(1, 359));
				}
				currentFails = 0;
				return random(750, 1000);
			} else {
				final RSTile destination = randomizeTile(fishingSpot
						.getLocation(), 2, 2);
				walkTileMM(destination);
				return random(500, 1000);
			}
		}
	}

	public boolean takeBoatFromKaramja() {
		final RSNPC customsOfficer = getNearestNPCByID(380);
		findObject(242);
		final RSTile location = new RSTile(3031, 3217);

		if (!locationName.equals("Karamja")) {
			return false;
		}

		if (getInventoryCount(995) < 30) {
			log("Not enough GP for a boat ride.");
			if (checkForLogout()) {
				stopAllScripts();
			}
		}

		if (distanceTo(location) <= 2
				&& !getMyPlayer().getLocation().equals(new RSTile(3029, 3217))) {
			if (tileOnScreen(location)) {
				atTile(location, "Cross");
				log("Arriving at Port Sarim.");
				return true;
			} else {
				walkTileMM(randomizeTile(location, 2, 2));
				return true;
			}
		}

		if (RSInterface.getInterface(228).isValid()) {
			atInterface(RSInterface.getInterface(228).getChild(2));
			return true;
		}
		if (RSInterface.getInterface(242).isValid()) {
			atInterface(RSInterface.getInterface(242).getChild(6));
			return true;
		}

		if (RSInterface.getInterface(230).isValid()) {
			atInterface(RSInterface.getInterface(230).getChild(3));
			return true;
		}

		if (RSInterface.getInterface(241).isValid()) {
			atInterface(RSInterface.getInterface(241).getChild(5));
			return true;
		}

		if (RSInterface.getInterface(64).isValid()) {
			atInterface(RSInterface.getInterface(64).getChild(5));
			return true;
		}

		if (RSInterface.getInterface(228).isValid()) {
			atInterface(RSInterface.getInterface(228).getChild(2));
			return false;
		}

		if (RSInterface.getInterface(241).isValid()) {
			atInterface(RSInterface.getInterface(241).getChild(5));
			return false;
		}

		if (customsOfficer != null) {
			if (tileOnScreen(customsOfficer.getLocation())) {
				atNPC(customsOfficer, "Pay-Fare");
				return true;
			} else {
				walkTileMM(randomizeTile(customsOfficer.getLocation(), 2, 2));
				return true;
			}
		}

		return false;
	}

	public boolean takeBoatToKaramja() {
		final int[] seamanIDs = new int[] { 376, 377, 378 }; // Pay-fare
		final RSNPC seaman = getNearestNPCByID(seamanIDs);
		final RSObject plank = findObject(2082);

		if (!locationName.equals("Karamja")) {
			return false;
		}

		if (getInventoryCount(995) < 30) {
			log("Not enough GP for a boat ride.");
			stopAllScripts();
		}

		if (plank != null) {
			log("Arriving at Karamja.");
			atObject(plank, "Cross");
			return true;
		}

		if (RSInterface.getInterface(64).isValid()) {
			atInterface(RSInterface.getInterface(64).getChild(5));
			return true;
		}

		if (RSInterface.getInterface(228).isValid()) {
			atInterface(RSInterface.getInterface(228).getChild(2));
			return true;
		}

		if (RSInterface.getInterface(241).isValid()) {
			atInterface(RSInterface.getInterface(241).getChild(5));
			return true;
		}
		if (seaman != null) {
			if (tileOnScreen(seaman.getLocation())) {
				atNPC(seaman, "Pay-fare");
				return true;
			} else {
				walkTileMM(randomizeTile(seaman.getLocation(), 2, 2));
				return true;
			}
		}

		return false;
	}

	public int useBank() {
		final RSObject bankBooth = findObject(bankID);

		if (getMyPlayer().isMoving()) {
			return random(250, 500);
		}

		if (runningFromCombat) {
			state = S_WALKTO_SPOT;
			return random(500, 750);
		}

		if (RSInterface.getInterface(Constants.INTERFACE_BANK).isValid()) {
			state = S_DEPOSIT;
			return 500;
		}

		if (bankBooth != null) {
			turnToObject(bankBooth, 40);
			if (atObject(bankBooth, "Use-quickly")) {
				log("Accessed bank account.");
				state = S_DEPOSIT;
				currentFails = 0;
				return random(500, 1000);
			} else {
				setCameraRotation(getCameraAngle() + random(-50, 50));
				log("Misclicked bank, trying again.");
				currentFails++;
				return random(500, 750);
			}
		} else {
			log("Unable to find bankbooth");
			currentFails++;
			return random(500, 750);
		}
	}

	public int useBankNPC() {
		final RSNPC banker = getNearestNPCByID(bankID);

		if (getMyPlayer().isMoving()) {
			return random(250, 500);
		}

		if (runningFromCombat) {
			state = S_WALKTO_SPOT;
			return random(500, 750);
		}

		if (RSInterface.getInterface(Constants.INTERFACE_BANK).isValid()) {
			state = S_DEPOSIT;
			return 500;
		}

		if (banker != null) {
			if (atNPC(banker, "Bank Banker")) {
				log("accessed bank account.");
				state = S_DEPOSIT;
				currentFails = 0;
				return random(500, 1000);
			} else {
				log("Misclicked bank, trying again.");
				currentFails++;
				return random(500, 750);
			}
		} else {
			log("Unable to find bankbooth");
			currentFails++;
			return random(500, 750);
		}

	}

	public int useBankNPCPiscatoris() {
		final RSNPC banker = getNearestNPCByID(bankID);

		if (getMyPlayer().isMoving()) {
			return random(250, 500);
		}

		if (runningFromCombat) {
			state = S_WALKTO_SPOT;
			return random(500, 750);
		}

		if (RSInterface.getInterface(Constants.INTERFACE_BANK).isValid()) {
			state = S_DEPOSIT;
			return 500;
		}

		if (banker != null) {
			if (atNPC(banker, "Bank Arnold Lydspor")) {
				log("accessed bank account.");
				state = S_DEPOSIT;
				currentFails = 0;
				return random(500, 1000);
			} else {
				log("Misclicked bank, trying again.");
				currentFails++;
				return random(500, 750);
			}
		} else {
			log("Unable to find bankbooth");
			currentFails++;
			return random(500, 750);
		}

	}

	public int walkToBank() {
		if (takeBoatFromKaramja()) {
			return random(1000, 1500);
		}

		// TODO: bug fix.
		/*
		 * if ( distanceTo(new RSTile(2953, 3147)) <= 4 ) return random(250,
		 * 500);
		 */

		if (randomRunEnergy <= getEnergy() && !isRunning()) {
			setRun(true);
			randomRunEnergy = random(20, 60);
			return random(750, 1000);
		}

		if (runningFromCombat && !getMyPlayer().isInCombat()) {
			log("No longer in combat, heading back to fishing spots.");
			state = S_WALKTO_SPOT;
			runningFromCombat = false;
			return random(250, 750);
		}

		if (distanceTo(toBank[toBank.length - 1]) <= 2) {

			log("Arriving at bank, accessing account.");
			state = S_USE_BANK;
			return random(750, 1500);
		}

		if (!getMyPlayer().isMoving() || getDestination() != null
				&& distanceTo(getDestination()) < 3) {
			walkPathMM(randomizePath(toBank, 2, 2), 20);
		}

		return random(50, 150);
	}

	public int walkToSpots() {
		if (takeBoatToKaramja()) {
			return random(1000, 1500);
		}

		if (randomRunEnergy <= getEnergy() && !isRunning()) {
			setRun(true);
			randomRunEnergy = random(20, 60);
			return random(750, 1000);
		}

		if (distanceTo(toArea[toArea.length - 1]) <= 3) {
			log("Arriving at fishing spots, continuing to fish.");
			state = S_FISH;
			currentFails = 0;
			return random(250, 750);
		}

		if (!getMyPlayer().isMoving()) {
			walkPathMM(randomizePath(toArea, 2, 2), 20);
		}

		return random(50, 150);
	}
}